/*
 * Copyright (c) 2002-2003 by OpenSymphony
 * All rights reserved.
 */
package org.jackysoft.opensymphony.workflow.entity;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.jackysoft.util.ReflectionUtil;
import org.jackysoft.util.XMLizable;

import com.google.gson.annotations.Expose;


/**
 * User: hani
 * Date: May 28, 2003
 * Time: 12:44:54 AM
 */

public abstract class AbstractDescriptor implements XMLizable, Serializable {
	protected Log logger = LogFactory.getLog("com.opensymphony.entiry.AbstractDescriptor");
    /**
	 * 
	 */
	private static final long serialVersionUID = -5961490844478392548L;
	//~ Instance fields ////////////////////////////////////////////////////////

    private AbstractDescriptor parent;
    private boolean hasId = false;
    @Expose
    private int entityId;
    @Expose
    private int id;

    
    protected org.dom4j.Element element;
    public AbstractDescriptor(){}
    
    public AbstractDescriptor(org.dom4j.Element adc){
    	element = adc;
    	init(adc);
    }
    protected abstract void init(Element adc);
    
    //~ Methods ////////////////////////////////////////////////////////////////

    public void setEntityId(int entityId) {
        this.entityId = entityId;
    }

   
    public int getEntityId() {
        return entityId;
    }

    public void setId(int id) {
        this.id = id;
        hasId = true;
    }

    public int getId() {
        return id;
    }

    public void setParent(AbstractDescriptor parent) {
        this.parent = parent;
    }

   
    public AbstractDescriptor getParent() {
        return parent;
    }

    public String asXML() {
        StringWriter stringWriter = new StringWriter();
        PrintWriter writer = new PrintWriter(stringWriter);
        this.writeXML(writer);
        writer.close();

        return stringWriter.toString();
    }

    public boolean hasId() {
        return hasId;
    }
    /**
     * @param container 当前元素
     * @param parentName 例如 validators
     * @param name 例如validator
     * @param cls 所要构建的元素的class类型，例如 AbstractDescriptor.class
     * @param objs 集合，例如,new ArrayList();
     * @param parent 所创建元素的parent 一般是AbstractDescriptor的子类
     * 
     * */
    protected void buildElement(org.dom4j.Element container,String parentName,String name,Class cls,List objs,Object parent){
    	if(container==null)return;
    	org.dom4j.Element tops = container.element(parentName);
    	buildElements(tops,name,cls,objs,parent);
    }
    
    protected void buildElement(org.dom4j.Element container,String parentName,String name,Class cls,List objs,Object parentCon,BuildCallback buildcallback){
    	if(container==null)return;
    	org.dom4j.Element tops = container.element(parentName);
    	buildElements(tops,name,cls,objs,parentCon,buildcallback);
    	
    }
    protected void buildElement(org.dom4j.Element container,String parentName,String name,Class cls,Object parentCon,BuildCallback buildcallback){
    	if(container==null)return;
    	org.dom4j.Element tops = container.element(parentName);
    	buildElements(tops,name,cls,null,parentCon,buildcallback);
    	
    }
    
    protected void buildElements(org.dom4j.Element container,String name,Class cls,List objs,Object parentCon,BuildCallback buildcallback){
    	if(container==null)return;
    	for(Iterator vitr = container.elementIterator(name);vitr.hasNext();){
    		org.dom4j.Element ve = (org.dom4j.Element) vitr.next();
    		Object obj = ReflectionUtil.construct(cls, ve,org.dom4j.Element.class,"init");
    		
    		ReflectionUtil.invokeMethod(obj, "setParent", new Class<?>[]{AbstractDescriptor.class}, new Object[]{parentCon});
    		if(objs!=null)objs.add(obj);
    		buildcallback.doExecute(obj, ve);
    	}
    }
    protected void buildElements(org.dom4j.Element container,String name,Class cls,List objs,Object parentCon){
    	if(container==null)return;    	
    	for(Iterator vitr = container.elementIterator(name);vitr.hasNext();){
			org.dom4j.Element ve = (org.dom4j.Element) vitr.next();	
			Object obj = ReflectionUtil.construct(cls, ve,org.dom4j.Element.class,"init");
			ReflectionUtil.invokeMethod(obj, "setParent", new Class<?>[]{AbstractDescriptor.class}, new Object[]{parentCon});
			objs.add(obj);
		}
    }
    /**
     * @param buildCallback  回调处理
     * */
    protected void buildElements(org.dom4j.Element container,String name,Class cls,Object parentCon,BuildCallback buildCallback){
    	if(container==null)return;
    	for(Iterator vitr = container.elementIterator(name);vitr.hasNext();){
    		org.dom4j.Element ve = (org.dom4j.Element) vitr.next();
    		Object obj = ReflectionUtil.construct(cls, ve,org.dom4j.Element.class,"init");
    		ReflectionUtil.invokeMethod(obj, "setParent", new Class<?>[]{AbstractDescriptor.class}, new Object[]{parentCon});
    		buildCallback.doExecute(obj,ve);
    	}
    }

	@Override
	public void writeXML(PrintWriter out) {
		OutputFormat format = OutputFormat.createPrettyPrint();
		XMLWriter writer =  new XMLWriter( out, format );
		try {
			writer.write(this.element);
		} catch (IOException e) {
			logger.error(e);
		}
		
	}
}
interface BuildCallback{
	public void doExecute(Object obj,org.dom4j.Element element);
	
}
